package com.cman777.springc.encode.advice;

import com.cman777.springc.encode.annotation.Encoding;
import com.google.common.base.Charsets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Optional;

/**
 * @author chenzhicong
 * @time 2020/4/15 10:32
 * @description 请求数据解密
 */
@Slf4j
public abstract class ARequestAdvice implements RequestBodyAdvice {


    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
                                           Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {

       	HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 获取注解配置是否解密字段
        Encoding apiEncode = parameter.getMethodAnnotation(Encoding.class);
        // 入参是否需要解密
        boolean needDecrypt = Optional.ofNullable(apiEncode).map(a -> a.decrypt()).orElse(true);
        if (needDecrypt && needDecryptOtherCondition()) {
            String s = decryptMessage2StringUTF8(request, IOUtils.toString(inputMessage.getBody(), Charsets.UTF_8));
            log.info("请求body明文：{}", s);
            return new DecryptInputMessage(inputMessage, s);
        } else {
            return inputMessage;
        }
    }

    /**
     * 附加解密条件
     */
    public abstract boolean needDecryptOtherCondition();

    /**
     * 解密
     */
    public abstract String decryptMessage2StringUTF8(HttpServletRequest request, String inputMessage);


    public static class DecryptInputMessage implements HttpInputMessage {
        private HttpHeaders headers;

        private InputStream body;


        public DecryptInputMessage(HttpInputMessage inputMessage, String content) {
            this.headers = inputMessage.getHeaders();
            this.body = IOUtils.toInputStream(content, Charsets.UTF_8);
        }

        @Override
        public InputStream getBody() {
            return body;
        }

        @Override
        public HttpHeaders getHeaders() {
            return headers;
        }
    }
}
